package com.hup.vd.view.customView;

import com.hup.utils.commons.DateBuilder;
import com.hup.utils.commons.hardware.HRobotJni;
import com.hup.utils.commons.hardware.MouseUtil;
import com.hup.utils.commons.start.DialogHelper;
import com.hup.utils.commons.start.LookThemeUtil;
import com.hup.utils.swing.ColorUtil;
import com.hup.utils.swing.FrameUtil;
import com.hup.utils.swing.customView.ImageButton;
import com.hup.utils.swing.model.ButtonGroupMulti;
import com.hup.utils.swing.model.ButtonGroupMulti.ButtonModelGetter;
import com.hup.utils.swing.model.ButtonModelMulti;
import com.hup.vd.constant.TaskConstant.TaskState;
import com.hup.vd.model.config.TaskInfo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.border.TitledBorder;
import javax.swing.plaf.FontUIResource;
import javax.swing.text.StyleContext;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.Locale;

/**
 * @author hugan
 * @date 2022/1/11
 */
@Slf4j
public class TaskItemView extends JPanel implements ButtonModelGetter {

    private static final String ERR_FILE_DELETED = "已删除";
    private static final String ERR_HAS_TASK_ERR = "下载异常";

    private static final Color DEF_BACKGROUND = new JLabel().getBackground();

    public JPanel root;
    public JLabel txtFileName;
    public JLabel txtParent;
    public JLabel txtProgress;
    public JProgressBar progressBar;
    public ImageButton btnStart;
    public ImageButton btnStop;
    public ImageButton btnOpenDir;
    public ImageButton btnOpenFile;
    public JLabel txtTaskState;
    public JLabel txtUseTime;
    public JLabel txtErrMsg;
    public JLabel txtNetSpeed;

    @Getter
    private TaskInfo task;

    /**
     * 必须设置
     */
    @Setter
    private ItemHandler itemHandler;
    @Getter
    private ButtonModelMulti model;
    private ButtonGroupMulti buttonGroup;

    public TaskItemView() {
        $$$setupUI$$$();
        model = new ButtonModelMulti(this);
        initView();
        initListener();
    }

    public TaskItemView(TaskInfo task, ItemHandler itemHandler, ButtonGroupMulti buttonGroup) {
        this();
        this.itemHandler = itemHandler;
        this.buttonGroup = buttonGroup;
        setTask(task);
    }

    private void initView() {
        setFocusable(true);//支持响应键盘快捷键
        JLabel[] labels = {txtProgress, txtUseTime, txtNetSpeed, txtTaskState};
        Font smallFont = new Font(txtProgress.getFont().getName(), Font.PLAIN, (int) (12 * LookThemeUtil.getScreenScale()));
        Color fontColor = Color.GRAY;
        for (JLabel label : labels) {
            label.setForeground(fontColor);
            label.setFont(smallFont);
        }
        txtParent.setFont(smallFont);
        txtErrMsg.setFont(smallFont);

        //处理文本过长,避免ListView出现横向滚动条
        fixPreferredSize(txtFileName, 230);
        fixPreferredSize(txtParent, 231);
    }

    /**
     * @param width 缩放前的宽度
     */
    private void fixPreferredSize(JLabel label, int width) {
        int height = label.getFontMetrics(label.getFont()).getHeight();
        Dimension dimension = new Dimension((int) (width * LookThemeUtil.getScreenScale()), height);
        label.setPreferredSize(dimension);
    }

    private void initListener() {
        model.addChangeListener(e -> {
            //log.info("e={}", e);
            if (model.isSelected()) {
                setBackground(ColorUtil.DEF_SELECTED_COLOR);
            } else if (model.isRollover()) {
                setBackground(ColorUtil.DEF_MOUSE_IN_COLOR);
            } else {
                setBackground(DEF_BACKGROUND);
            }
        });
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                buttonGroup.mouseClicked(e, model);
                if (MouseUtil.isLeftButton(e)) {
                    if (e.getClickCount() == 1) {
                        itemHandler.onClickItem(task);
                        requestFocus();
                    } else if (e.getClickCount() == 2 && e.getModifiersEx() == 0) {
                        if (task.isWaitToPause()) return;
                        if (btnStart.isVisible()) {
                            itemHandler.switchTaskState(task, true);
                        } else if (btnStop.isVisible()) {
                            itemHandler.switchTaskState(task, false);
                        }
                    }
                } else if (MouseUtil.isRightButton(e)) {
                    itemHandler.showMenu(e, TaskItemView.this);
                }
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                model.setRollover(true);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                model.setRollover(false);
            }
        });

        ActionListener openFileListener = e -> {
            String file = null;
            try {
                if (e.getSource() == btnOpenFile) {
                    file = task.getFilePath();
                    HRobotJni.shellExecuteRun(task.getFilePath(), null);
                } else {
                    file = new File(task.getFilePath()).getParent();
                    HRobotJni.shellExecuteRun(file, null);
                }
            } catch (Exception ex) {
                if (task.getFinishedState()) {
                    btnOpenFile.setEnabled(false);
                    txtErrMsg.setText(ERR_FILE_DELETED);
                    txtErrMsg.setVisible(true);
                }
                DialogHelper.confirm("找不到文件:" + file)
                        .error()
                        .show(FrameUtil.getParentWindow(this));
            }
        };
        btnOpenFile.setActionListener(openFileListener);
        btnOpenDir.setActionListener(openFileListener);
        btnStart.setActionListener(e -> {
            itemHandler.onClickItem(task);
            itemHandler.switchTaskState(task, true);
        });
        btnStop.setActionListener(e -> {
            itemHandler.onClickItem(task);
            itemHandler.switchTaskState(task, false);
        });
    }

    private void createUIComponents() {
        root = this;
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        createUIComponents();
        root.setLayout(new GridBagLayout());
        root.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        progressBar = new JProgressBar();
        GridBagConstraints gbc;
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.gridwidth = 5;
        gbc.fill = GridBagConstraints.BOTH;
        root.add(progressBar, gbc);
        txtParent = new JLabel();
        txtParent.setText("父目录");
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 1;
        gbc.gridwidth = 2;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(0, 5, 0, 0);
        root.add(txtParent, gbc);
        btnOpenDir = new ImageButton();
        btnOpenDir.setPadding(2);
        btnOpenDir.setShareIcon("/img/icon_dir.png");
        btnOpenDir.setToolTipText("打开目录");
        btnOpenDir.setUnitedIconHeight(1.0f);
        btnOpenDir.setUnitedIconWidth(1.0f);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.EAST;
        root.add(btnOpenDir, gbc);
        btnOpenFile = new ImageButton();
        btnOpenFile.setPadding(2);
        btnOpenFile.setShareIcon("/img/icon_play.png");
        btnOpenFile.setToolTipText("打开文件");
        btnOpenFile.setUnitedIconHeight(1.5f);
        btnOpenFile.setUnitedIconWidth(1.5f);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = new Insets(0, 10, 0, 0);
        root.add(btnOpenFile, gbc);
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridBagLayout());
        panel1.setOpaque(false);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.gridwidth = 5;
        gbc.fill = GridBagConstraints.BOTH;
        root.add(panel1, gbc);
        txtProgress = new JLabel();
        txtProgress.setText("1/200");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(0, 20, 0, 0);
        panel1.add(txtProgress, gbc);
        txtUseTime = new JLabel();
        txtUseTime.setText("耗时");
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(0, 20, 0, 20);
        panel1.add(txtUseTime, gbc);
        txtTaskState = new JLabel();
        txtTaskState.setText("任务状态");
        gbc = new GridBagConstraints();
        gbc.gridx = 3;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(0, 0, 0, 20);
        panel1.add(txtTaskState, gbc);
        txtNetSpeed = new JLabel();
        txtNetSpeed.setText("0KB/s");
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(0, 0, 0, 20);
        panel1.add(txtNetSpeed, gbc);
        btnStart = new ImageButton();
        btnStart.setShareIcon("/img/icon_download.png");
        btnStart.setToolTipText("下载");
        btnStart.setUnitedIconHeight(2.0f);
        btnStart.setUnitedIconWidth(2.0f);
        gbc = new GridBagConstraints();
        gbc.gridx = 3;
        gbc.gridy = 0;
        gbc.gridheight = 2;
        gbc.insets = new Insets(0, 0, 0, 10);
        root.add(btnStart, gbc);
        btnStop = new ImageButton();
        btnStop.setShareIcon("/img/icon_stop.png");
        btnStop.setToolTipText("暂停");
        btnStop.setUnitedIconHeight(2.0f);
        btnStop.setUnitedIconWidth(2.0f);
        gbc = new GridBagConstraints();
        gbc.gridx = 4;
        gbc.gridy = 0;
        gbc.gridheight = 2;
        gbc.insets = new Insets(0, 0, 0, 10);
        root.add(btnStop, gbc);
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridBagLayout());
        panel2.setOpaque(false);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.SOUTH;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(0, 5, 0, 0);
        root.add(panel2, gbc);
        txtFileName = new JLabel();
        Font txtFileNameFont = this.$$$getFont$$$(null, Font.BOLD, -1, txtFileName.getFont());
        if (txtFileNameFont != null) txtFileName.setFont(txtFileNameFont);
        txtFileName.setText("文件名");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.SOUTHWEST;
        panel2.add(txtFileName, gbc);
        txtErrMsg = new JLabel();
        txtErrMsg.setForeground(new Color(-65536));
        txtErrMsg.setText("错误消息");
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.SOUTHWEST;
        panel2.add(txtErrMsg, gbc);
    }

    /**
     * @noinspection ALL
     */
    private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) {
        if (currentFont == null) return null;
        String resultName;
        if (fontName == null) {
            resultName = currentFont.getName();
        } else {
            Font testFont = new Font(fontName, Font.PLAIN, 10);
            if (testFont.canDisplay('a') && testFont.canDisplay('1')) {
                resultName = fontName;
            } else {
                resultName = currentFont.getName();
            }
        }
        Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize());
        boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac");
        Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize());
        return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return root;
    }

    /**
     * 初始化数据
     */
    public void setTask(TaskInfo task) {
        this.task = task;
        task.setView(this);
        notifyTaskUpdated();
    }

    public void notifyTaskUpdated() {
        boolean finished = task.getFinishedState();
        File file = new File(task.getFilePath());
        boolean existsFile = file.exists() && !file.isDirectory();
        //
        btnOpenFile.setEnabled(finished && existsFile);
        txtFileName.setText(task.getShortName());
        txtParent.setText(file.getParentFile().getName());
        //
        btnStart.setVisible(TaskState.PAUSE == task.getTaskState());
        btnStop.setVisible(task.isRunning());
        btnStop.setEnabled(!task.isWaitToPause());
        //
        if (!task.isWaitToPause()) {
            txtTaskState.setText(task.getTaskState().state);
        } else {
            txtTaskState.setText("正在暂停...");
        }
        progressBar.setMaximum(task.getProgressMax());
        progressBar.setValue(task.getProgressValue());
        if (!finished) {
            txtProgress.setText(task.getProgressValue() + "/" + task.getProgressMax());
        } else {
            txtProgress.setText(task.getFileSizeStr());
        }
        if (task.getUsedTime() == null) {
            txtUseTime.setText("--:--");
        } else if (!task.getFinishedState()) {
            txtUseTime.setText(spanChar(task.getUsedTime()));
        } else {
            txtUseTime.setText(spanChar(task.getUsedTime()) + " " + DateBuilder.ymdHms(task.getFinishTime()));
        }
        //网速
        if (TaskState.DOWNLOAD != task.getTaskState()) {
            txtNetSpeed.setText("");
        } else {
            txtNetSpeed.setText(FileUtils.byteCountToDisplaySize(task.getNetSpeedCounter().getLastPick() * 1024L).replace(" ", "") + "/s");
        }
        //错误消息
        String errMsg = null;
        if (!finished) {
            if (task.getTaskErr() != null) errMsg = ERR_HAS_TASK_ERR;
        } else {
            if (!existsFile) errMsg = ERR_FILE_DELETED;
        }
        if (errMsg != null) {
            txtErrMsg.setVisible(true);
            txtErrMsg.setText(errMsg);
        } else {
            txtErrMsg.setVisible(false);
        }
    }

    /**
     * @return 最多展示2级时间
     */
    private String spanChar(long ms) {
        if (ms == 0) return "0秒";
        StringBuilder sb = new StringBuilder();
        int blockCount = 0;
        int s = (int) (ms / 1000);
        if (s >= 86400) {
            int day = s / 86400;
            sb.append(day).append("天");
            blockCount++;
        }
        if (s >= 3600) {
            int h = s % 86400 / 3600;
            sb.append(h).append("小时");
            blockCount++;
            if (blockCount == 2) return sb.toString();
        }
        if (s >= 60) {
            int m = s % 3600 / 60;
            sb.append(m).append("分");
            blockCount++;
            if (blockCount == 2) return sb.toString();
        }
        s = s % 60;
        if (s != 0) {
            sb.append(s).append("秒");
        }
        return sb.toString();
    }

    public interface ItemHandler {

        void onClickItem(TaskInfo task);

        void showMenu(MouseEvent e, TaskItemView view);

        /**
         * 开始或暂停任务,双击/点击按钮
         */
        void switchTaskState(TaskInfo task, boolean isStart);

    }

}
